;; The first four lines of this file were added by Dracula.
;; They tell DrScheme that this is a Dracula Modular ACL2 program.
;; Leave these lines unchanged so that DrScheme can properly load this file.
#reader(planet "reader.rkt" ("cce" "dracula.plt") "modular" "lang")
(require "ifisheye.lisp")
(require "icommon.lisp")
(require "iimage.lisp")

(module MFisheye
  (include-book "avl-rational-keys" :dir :teachpacks)
  (import ICommon)
  (import IImage)
  
  (defun GetRadialX(x y cx cy k xscale xshift yscale yshift)
    (let* ((x (+ xshift (* x xscale)))
           (y (+ yshift (* y yscale)))
           (result (+ x (* (- x cx) k (+ (* (- x cx) (- x cx)) (* (- y cy) (- y cy)))))))
      result))
  
  (defun GetRadialY(x y cx cy k xscale xshift yscale yshift)
    (let* ((x (+ xshift (* x xscale)))
           (y (+ yshift (* y yscale)))
           (result (+ y (* (- y cy) k (+ (* (- x cx) (- x cx)) (* (- y cy) (- y cy)))))))
      result))
  
  (defun CalcShift(x1 x2 cx k)
    (let* ((x3 (+ x1 (* (- x2 x1) 0.5)))
          (res1 (+ x1 (* (* k (- x1 cx)) (* (- x1 cx) (- x1 cx)))))
          (res3 (+ x3 (* (* k (- x3 cx)) (* (- x3 cx) (- x3 cx))))))
      (if (and (< res1 1) (> res1 -1))
          x1
          (if (< res3 0)
              (CalcShift x3 x2 cx k)
              (CalcShift x1 x3 cx k)))))
  
  (defun SampleImage(tree x y)
    (if (isValidPixel (1+ x) (1+ y) (getWidth tree) (getHeight tree))
        (getPixel tree (1+ x) (1+ y))
        (list 0 0 0)))
  
  (defun FisheyeHelper (x y width height oldtree newtree k xscale xshift yscale yshift centerX centerY)
    (let* ((nextX (getNextXCoordinate x width))
           (nextY (getNextYCoordinate x y width))
           (sampleX (floorNumber (GetRadialX (1- x) (1- y) centerX centerY k xscale xshift yscale yshift)))
           (sampleY (floorNumber (GetRadialY (1- x) (1- y) centerX centerY k xscale xshift yscale yshift)))
           (samplePixel (SampleImage oldtree sampleX sampleY)))
        (if (isValidPixel nextX nextY width height)
            (FisheyeHelper nextX nextY width height oldtree (InsertPixelAsRGBList newtree x y samplePixel)
                           k xscale xshift yscale yshift centerX centerY)
            newtree)))
  
  (defun Fisheye (width height oldtree newtree k)
    (let* ((centerX (/ width 2))
           (centerY (/ height 2))
           (xshift (CalcShift 0 (1- centerX) centerX k))
           (newCenterX (- width centerX))
           (xshift2 (CalcShift 0 (1- newCenterX) newCenterX k))
           (yshift (CalcShift 0 (1- centerY) centerY k))
           (newCenterY (- height centerY))
           (yshift2 (CalcShift 0 (1- newCenterY) newCenterY k))
           (xscale (/ (- (- width xshift) xshift2) width))
           (yscale (/ (- (- height yshift) yshift2) height)))
      (FisheyeHelper 1 height width height oldtree newtree k xscale xshift yscale yshift centerX centerY)))
  
  (defun MainFisheye (tree)
    (let* ((header (getHeader tree))
           (height (getHeight tree))
           (width (getWidth tree))
           (tmptree (avl-insert (empty-tree) -1 header))
           (newtree (setHeight (setWidth tmptree width) height)))
      (mv (Fisheye width height tree tree 0.002) (list "Sucessfully applied fisheye distortion to image."))))
  
  (export IFisheye))